package com.klikmee.sms.core.commons.exceptions;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class ErrorInfo {

	/**
	 * The errorType field tells whether the error was caused by errornous input
	 * to the application, an external service that failed, or an internal
	 * error.
	 * 
	 */
	public enum ErrorType {
		CLIENT, INTERNAL, EXTERNAL
	}

	/**
	 * Contains the severity of the error. E.g. WARNING, ERROR, FATAL etc. It is
	 * up to you to define the severity levels for your application.
	 * 
	 */
	public enum Severity {
		WARNING, ERROR, FATAL
	}

	/**
	 * Cause of the error
	 */
	protected Throwable				cause					= null;
	/**
	 * A unique id that identifies this error. The errorId tells what went
	 * wrong, like FILE_LOAD_ERROR.
	 */
	protected String				errorId					= null;
	/**
	 * A unique id that identifies the context where the error occurred. The
	 * contextId tells where the error occurred (in what class, component, layer
	 * etc.)
	 */
	protected String				contextId				= null;

	protected ErrorType				errorType				= null;
	protected Severity				severity				= null;

	protected String				userErrorDescription	= null;
	protected String				errorDescription		= null;
	protected String				errorCorrection			= null;

	protected Map<String, Object>	parameters				= new HashMap<String, Object>();
	
	
	public Throwable getCause() {
		return cause;
	}


	public void setCause(Throwable cause) {
		this.cause = cause;
	}


	public String getErrorId() {
		return errorId;
	}


	public void setErrorId(String errorId) {
		this.errorId = errorId;
	}


	public String getContextId() {
		return contextId;
	}


	public void setContextId(String contextId) {
		this.contextId = contextId;
	}


	public ErrorType getErrorType() {
		return errorType;
	}


	public void setErrorType(ErrorType errorType) {
		this.errorType = errorType;
	}


	public Severity getSeverity() {
		return severity;
	}


	public void setSeverity(Severity severity) {
		this.severity = severity;
	}


	public String getUserErrorDescription() {
		return userErrorDescription;
	}


	public void setUserErrorDescription(String userErrorDescription) {
		this.userErrorDescription = userErrorDescription;
	}


	public String getErrorDescription() {
		return errorDescription;
	}


	public void setErrorDescription(String errorDescription) {
		this.errorDescription = errorDescription;
	}


	public String getErrorCorrection() {
		return errorCorrection;
	}


	public void setErrorCorrection(String errorCorrection) {
		this.errorCorrection = errorCorrection;
	}


	public Map<String, Object> getParameters() {
		return parameters;
	}


	public void setParameters(Map<String, Object> parameters) {
		this.parameters = parameters;
	}

	/**
	 * Extracts complete error id from exception.
	 * @param e exception for extract from
	 * @return string representation of error id
	 */
	public static String extractErrorId(ApplicationException e){
	    StringBuilder builder = new StringBuilder();

	    for(int i=e.getErrorInfoList().size()-1; i>=0; i--){

	        ErrorInfo errorInfo = e.getErrorInfoList().get(i);

	        builder.append(errorInfo.getContextId().toString());
	        builder.append(":");
	        builder.append(errorInfo.getErrorId().toString());

	        if(i>0){
	            builder.append("/");
	        }
	    }

	    return builder.toString();
	}
	
	/**
	 * Extracts all additional parameters from exception 
	 * properties from key=value
	 * @param exception exception to extract params from
	 * @return list of additional parameters
	 */
	public static String extractParameters(ApplicationException exception){
		StringBuilder result = new StringBuilder();
		result.append("Listing additional params:").append("\n");
		
		List<ErrorInfo> errorInfoList = exception.getErrorInfoList();
		for (ErrorInfo errorInfo : errorInfoList) {
			Map<String, Object> currentParams = errorInfo.getParameters();
			Set<Entry<String,Object>> entrySet = currentParams.entrySet();
			for (Entry<String, Object> entry : entrySet) {
				result.append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
			}
		}
		
		return result.toString();
	}
}
